#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <string.h>
#include <sys/select.h>

int main(int argc, char *argv[]) {
    int fd; // 文件描述符
    struct termios options, oldterm;
    char tx_buf[] = "Hello Serial Port!"; // 要发送的数据
    char rx_buf[100]; // 接收缓冲区
    char *dev_file = "/dev/ttyS4"; // 默认的串口设备文件

    if (argc > 1) {
        dev_file = argv[1];
    }

    // 打开串口设备文件
    printf("opening: %s\n", dev_file);
    fd = open(dev_file, O_RDWR | O_NOCTTY); 
    if (fd == -1) {
        perror("open serial port");
        exit(1);
    }

    // 获取并修改串口属性
    tcgetattr(fd, &options);
    options.c_cflag = B115200 | CS8 | CLOCAL | CREAD;
    options.c_iflag = IGNPAR;
    // raw 模式
    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    options.c_iflag &= ~(INPCK | ICRNL | IXON | IXOFF);
    options.c_oflag &= ~OPOST;
    options.c_cc[VMIN] = 1;
    options.c_cc[VTIME] = 0;

    tcflush(fd, TCIFLUSH);
    tcsetattr(fd, TCSANOW, &options);

    // 设置标准输入为非缓冲模式
    tcgetattr(STDIN_FILENO, &oldterm);
    struct termios newterm = oldterm;
    newterm.c_lflag &= ~(ICANON | ECHO);
    tcsetattr(STDIN_FILENO, TCSANOW, &newterm);

    // 发送数据
    write(fd, tx_buf, sizeof(tx_buf));

    while (1) {
        // 监控标准输入和串口输入
        fd_set rfds;
        FD_ZERO(&rfds);
        FD_SET(0, &rfds); // 标准输入
        FD_SET(fd, &rfds); // 串口输入

        select(fd + 1, &rfds, NULL, NULL, NULL);

        // 处理标准输入
        if (FD_ISSET(0, &rfds)) {
            char c = getchar();
            write(fd, &c, 1); // 发送到串口
        }

        // 处理串口输入
        if (FD_ISSET(fd, &rfds)) {
            int n = read(fd, rx_buf, sizeof(rx_buf));
            if (n > 0) {
                rx_buf[n] = 0; // 添加字符串结束符
                printf("%s", rx_buf);
                fflush(stdout);
            }
        }
    }


    // 恢复标准输入的终端设置
    tcsetattr(STDIN_FILENO, TCSANOW, &oldterm);
    // 关闭串口
    close(fd);

    return 0;
}